use std::fmt::Debug;

trait Observer: Debug {
    fn update(&self, str: String);
    fn get_id(&self) -> String;
}

#[derive(Debug)]
struct Customer {
    id: String,
}

impl Observer for Customer {
    fn update(&self, str: String) {
        println!("Show Customer:{}->{:?}", self.id, str)
    }

    fn get_id(&self) -> String {
        return self.id.to_string();
    }
}

trait Subject {
    fn register(&mut self, ob: Box<dyn Observer>);
    fn deregister(&mut self, ob: Box<dyn Observer>);
    fn notify_all(&self);
}

#[derive(Debug)]
struct Item {
    observer_list: Vec<Box<dyn Observer>>,
    name: String,
    in_stock: bool,
}

impl Item {
    fn update_availability(mut self) {
        self.in_stock = true;
        self.notify_all()
    }
}

impl Subject for Item {
    fn register(&mut self, ob: Box<dyn Observer>) {
        println!("register {:?}", ob.get_id());
        self.observer_list.push(ob);
    }

    fn deregister(&mut self, ob: Box<dyn Observer>) {
        println!("register {:?}", ob.get_id());
        self.observer_list.retain(|x| {
            x.get_id() != ob.get_id()
        });
    }

    fn notify_all(&self) {
        for x in &self.observer_list {
            x.update(self.name.to_string())
        };
    }
}

#[test]
fn main() {
    let mut item = Item {
        observer_list: vec![],
        name: "asdad".to_string(),
        in_stock: false,
    };
    let customer = Box::new(Customer { id: "aa".to_string() });
    let customer2 = Box::new(Customer { id: "bb".to_string() });
    item.register(customer);
    println!("{:?}", item.observer_list);
    item.register(customer2);
    println!("{:?}", item.observer_list);
    let customer2 = Box::new(Customer { id: "bb".to_string() });
    let customer3 = Box::new(Customer { id: "cc".to_string() });
    item.deregister(customer2);
    item.register(customer3);

    println!("{:?}", item.observer_list);
    item.update_availability();
}